/**
 * 图片服务
 * 负责图片元数据提取、缩略图生成等图片处理功能
 */

import ExifReader from 'exifreader'
import sharp from 'sharp'
import path from 'path'

/**
 * EXIF元数据
 */
export interface ExifData {
  DateTimeOriginal?: string
  Make?: string
  Model?: string
  GPSLatitude?: number
  GPSLongitude?: number
  GPSAltitude?: number
  FNumber?: number
  ExposureTime?: number
  ISO?: number
  FocalLength?: number
  Flash?: boolean
  [key: string]: any
}

/**
 * 图片信息
 */
export interface ImageInfo {
  width: number
  height: number
  format: string
  size?: number
  colorSpace?: string
  hasAlpha?: boolean
  orientation?: number
  exif?: ExifData
}

/**
 * 图片服务类
 */
export class ImageService {
  /**
   * 获取图片基本信息
   * @param filePath 图片文件路径
   * @returns 图片信息
   */
  static async getImageInfo(filePath: string): Promise<ImageInfo> {
    try {
      const metadata = await sharp(filePath).metadata()
      const exifData = await this.extractExifData(filePath)

      return {
        width: metadata.width || 0,
        height: metadata.height || 0,
        format: metadata.format || path.extname(filePath).substring(1),
        size: metadata.size,
        colorSpace: metadata.space,
        hasAlpha: metadata.hasAlpha,
        orientation: metadata.orientation,
        exif: exifData
      }
    } catch (error) {
      console.error(`获取图片信息失败: ${filePath}`, error)
      // 返回默认信息
      return {
        width: 0,
        height: 0,
        format: path.extname(filePath).substring(1)
      }
    }
  }

  /**
   * 提取图片EXIF数据
   * @param filePath 图片文件路径
   * @returns EXIF数据
   */
  static async extractExifData(filePath: string): Promise<ExifData | undefined> {
    try {
      const buffer = await sharp(filePath).toBuffer()
      const tags = ExifReader.load(buffer)

      // 转换EXIF数据
      const exifData: ExifData = {}

      // 处理日期时间
      if (tags.DateTimeOriginal && tags.DateTimeOriginal.description) {
        exifData.DateTimeOriginal = tags.DateTimeOriginal.description
      }

      // 处理相机信息
      if (tags.Make && tags.Make.description) {
        exifData.Make = tags.Make.description
      }

      if (tags.Model && tags.Model.description) {
        exifData.Model = tags.Model.description
      }

      // 处理GPS信息
      if (tags.GPSLatitude && tags.GPSLongitude) {
        try {
          const lat = this.convertDMSToDD(tags.GPSLatitude.description, tags.GPSLatitudeRef?.description)
          const lon = this.convertDMSToDD(tags.GPSLongitude.description, tags.GPSLongitudeRef?.description)
          
          if (!isNaN(lat) && !isNaN(lon)) {
            exifData.GPSLatitude = lat
            exifData.GPSLongitude = lon
          }
        } catch (error) {
          console.error('GPS坐标转换失败', error)
        }
      }

      if (tags.GPSAltitude && tags.GPSAltitude.description) {
        try {
          const altitude = parseFloat(tags.GPSAltitude.description)
          if (!isNaN(altitude)) {
            exifData.GPSAltitude = altitude
          }
        } catch (error) {
          console.error('GPS高度转换失败', error)
        }
      }

      // 处理拍摄参数
      if (tags.FNumber && tags.FNumber.description) {
        const fNumber = parseFloat(tags.FNumber.description)
        if (!isNaN(fNumber)) {
          exifData.FNumber = fNumber
        }
      }

      if (tags.ExposureTime && tags.ExposureTime.description) {
        const exposureTime = parseFloat(tags.ExposureTime.description)
        if (!isNaN(exposureTime)) {
          exifData.ExposureTime = exposureTime
        }
      }

      if (tags.ISO && tags.ISO.description) {
        const iso = parseInt(tags.ISO.description, 10)
        if (!isNaN(iso)) {
          exifData.ISO = iso
        }
      }

      if (tags.FocalLength && tags.FocalLength.description) {
        const focalLength = parseFloat(tags.FocalLength.description)
        if (!isNaN(focalLength)) {
          exifData.FocalLength = focalLength
        }
      }

      if (tags.Flash && tags.Flash.description) {
        const flash = parseInt(tags.Flash.description, 10)
        exifData.Flash = !isNaN(flash) && (flash & 0x1) === 0x1
      }

      return exifData
    } catch (error) {
      console.error(`提取EXIF数据失败: ${filePath}`, error)
      return undefined
    }
  }

  /**
   * 生成缩略图
   * @param inputPath 输入图片路径
   * @param outputPath 输出缩略图路径
   * @param width 缩略图宽度
   * @param height 缩略图高度
   * @param quality 图片质量 (0-100)
   * @returns 是否生成成功
   */
  static async generateThumbnail(
    inputPath: string,
    outputPath: string,
    width: number,
    height: number,
    quality: number = 80
  ): Promise<boolean> {
    try {
      await sharp(inputPath)
        .resize(width, height, {
          fit: 'cover',
          position: 'center'
        })
        .jpeg({ quality })
        .toFile(outputPath)

      return true
    } catch (error) {
      console.error(`生成缩略图失败: ${inputPath} -> ${outputPath}`, error)
      return false
    }
  }

  /**
   * 生成预览图
   * @param inputPath 输入图片路径
   * @param outputPath 输出预览图路径
   * @param maxWidth 最大宽度
   * @param maxHeight 最大高度
   * @param quality 图片质量 (0-100)
   * @returns 是否生成成功
   */
  static async generatePreview(
    inputPath: string,
    outputPath: string,
    maxWidth: number,
    maxHeight: number,
    quality: number = 85
  ): Promise<boolean> {
    try {
      await sharp(inputPath)
        .resize(maxWidth, maxHeight, {
          fit: 'inside',
          withoutEnlargement: true
        })
        .jpeg({ quality })
        .toFile(outputPath)

      return true
    } catch (error) {
      console.error(`生成预览图失败: ${inputPath} -> ${outputPath}`, error)
      return false
    }
  }

  /**
   * 旋转图片
   * @param inputPath 输入图片路径
   * @param outputPath 输出图片路径
   * @param angle 旋转角度
   * @returns 是否旋转成功
   */
  static async rotateImage(inputPath: string, outputPath: string, angle: number): Promise<boolean> {
    try {
      await sharp(inputPath)
        .rotate(angle)
        .toFile(outputPath)

      return true
    } catch (error) {
      console.error(`旋转图片失败: ${inputPath} -> ${outputPath}`, error)
      return false
    }
  }

  /**
   * 裁剪图片
   * @param inputPath 输入图片路径
   * @param outputPath 输出图片路径
   * @param left 左边距
   * @param top 上边距
   * @param width 裁剪宽度
   * @param height 裁剪高度
   * @returns 是否裁剪成功
   */
  static async cropImage(
    inputPath: string,
    outputPath: string,
    left: number,
    top: number,
    width: number,
    height: number
  ): Promise<boolean> {
    try {
      await sharp(inputPath)
        .extract({ left, top, width, height })
        .toFile(outputPath)

      return true
    } catch (error) {
      console.error(`裁剪图片失败: ${inputPath} -> ${outputPath}`, error)
      return false
    }
  }

  /**
   * 调整图片大小
   * @param inputPath 输入图片路径
   * @param outputPath 输出图片路径
   * @param width 目标宽度
   * @param height 目标高度
   * @param fit 调整方式
   * @returns 是否调整成功
   */
  static async resizeImage(
    inputPath: string,
    outputPath: string,
    width: number,
    height: number,
    fit: 'cover' | 'contain' | 'fill' | 'inside' | 'outside' = 'cover'
  ): Promise<boolean> {
    try {
      await sharp(inputPath)
        .resize(width, height, { fit })
        .toFile(outputPath)

      return true
    } catch (error) {
      console.error(`调整图片大小失败: ${inputPath} -> ${outputPath}`, error)
      return false
    }
  }

  /**
   * 将度分秒格式转换为十进制度数
   * @param dms 度分秒格式字符串
   * @param ref 方向引用 (N/S, E/W)
   * @returns 十进制度数
   */
  private static convertDMSToDD(dms: string | undefined, ref: string | undefined): number {
    if (!dms) return NaN

    try {
      // 解析度分秒格式，例如 "30 deg 15' 30""
      const parts = dms.match(/(\d+)\s*deg\s*(\d+)'\s*(\d+(?:\.\d+)?)/)
      if (!parts || parts.length < 4) return NaN

      const degrees = parseInt(parts[1], 10)
      const minutes = parseInt(parts[2], 10)
      const seconds = parseFloat(parts[3])

      let dd = degrees + minutes / 60 + seconds / 3600

      // 根据方向调整符号
      if (ref) {
        if (ref === 'S' || ref === 'W') {
          dd = dd * -1
        }
      }

      return dd
    } catch (error) {
      console.error('度分秒转换失败', error)
      return NaN
    }
  }

  /**
   * 检查文件是否为支持的图片格式
   * @param filePath 文件路径
   * @returns 是否为支持的图片格式
   */
  static isSupportedImage(filePath: string): boolean {
    const ext = path.extname(filePath).toLowerCase()
    const supportedExtensions = [
      '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.heic', '.heif', '.raw'
    ]
    return supportedExtensions.includes(ext)
  }

  /**
   * 获取图片格式
   * @param filePath 文件路径
   * @returns 图片格式
   */
  static async getImageFormat(filePath: string): Promise<string> {
    try {
      const metadata = await sharp(filePath).metadata()
      return metadata.format || path.extname(filePath).substring(1)
    } catch (error) {
      console.error(`获取图片格式失败: ${filePath}`, error)
      return path.extname(filePath).substring(1)
    }
  }
}